#define _CRT_SECURE_NO_WARNINGS

#include "tileset.h"

#include "common.h"

#include <cmath>
#include <vector>
#include <string>

using namespace std;

static const double pi = acos(-1);

double tileset::degree2rad(double val) {
	return val * pi / 180.0;
}

double tileset::longti_to_meter(double diff, double lati) {
	return diff / 0.000000156785 * cos(lati);
}

double tileset::lati_to_meter(double diff) {
	return diff / 0.000000157891;
}

double tileset::meter_to_longti(double m, double lati) {
	return m * 0.000000156785 / cos(lati);
}

double tileset::meter_to_lati(double m) {
	return m * 0.000000157891;
}

double tileset::write_tileset(double radian_x, double radian_y, double tile_w, double tile_h, double height_min, double height_max,
	double geometricError, const char* filename, const char* full_path) {

	double ellipsod_a = 40680631590769;
	double ellipsod_b = 40680631590769;
	double ellipsod_c = 40408299984661.4;

	const double pi = acos(-1);
	double xn = cos(radian_x) * cos(radian_y);
	double yn = sin(radian_x) * cos(radian_y);
	double zn = sin(radian_y);

	double x0 = ellipsod_a * xn;
	double y0 = ellipsod_b * yn;
	double z0 = ellipsod_c * zn;
	double gamma = sqrt(xn * x0 + yn * y0 + zn * z0);
	double px = x0 / gamma;
	double py = y0 / gamma;
	double pz = z0 / gamma;
	double dx = x0 * height_min;
	double dy = y0 * height_min;
	double dz = z0 * height_min;

	vector<double> east_mat = { -y0,x0,0 };
	vector<double> north_mat = {
		(y0 * east_mat[2] - east_mat[1] * z0),
		(z0 * east_mat[0] - east_mat[2] * x0),
		(x0 * east_mat[1] - east_mat[0] * y0)
	};
	double east_normal = sqrt(
		east_mat[0] * east_mat[0] +
		east_mat[1] * east_mat[1] +
		east_mat[2] * east_mat[2]
	);
	double north_normal = sqrt(
		north_mat[0] * north_mat[0] +
		north_mat[1] * north_mat[1] +
		north_mat[2] * north_mat[2]
	);

	vector<double> matrix = {
		east_mat[0] / east_normal,
		east_mat[1] / east_normal,
		east_mat[2] / east_normal,
		0,
		north_mat[0] / north_normal,
		north_mat[1] / north_normal,
		north_mat[2] / north_normal,
		0,
		xn,
		yn,
		zn,
		0,
		px + dx,
		py + dy,
		pz + dz,
		1
	};

	vector<double> region = {
		radian_x - meter_to_longti(tile_w / 2, radian_y),
		radian_y - meter_to_lati(tile_h / 2),
		radian_x + meter_to_longti(tile_w / 2, radian_y),
		radian_y + meter_to_lati(tile_h / 2),
		0,
		height_max
	};

	string json_txt = "{\"asset\": {\
        \"version\": \"0.0\",\
        \"gltfUpAxis\": \"Y\"\
    },\
    \"geometricError\":";
	json_txt += to_string(geometricError);
	json_txt += ",\"root\": {\
        \"transform\": [";
	for (int i = 0; i < 15; i++) {
		json_txt += to_string(matrix[i]);
		json_txt += ",";
	}
	json_txt += "1],\
    \"boundingVolume\": {\
    \"region\": [";
	for (int i = 0; i < 5; i++) {
		json_txt += to_string(region[i]);
		json_txt += ",";
	}
	json_txt += to_string(region[5]);

	char last_buf[512];
	sprintf(last_buf, "]},\"geometricError\": %f,\
        \"refine\": \"REPLACE\",\
        \"content\": {\
        \"uri\": \"%s\"}}}", geometricError, filename);

	json_txt += last_buf;

	common com;
	bool ret = com.write_file(full_path, json_txt.data(), (unsigned long)json_txt.size());
	return ret;
};
